package vcp.server.requesthandler;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import ocsf.server.ConnectionToClient;

import org.joda.time.Minutes;

import vcp.client.forms.SubscriptionForm;
import vcp.client.request.SubmitSubscriptionFormRequest;
import vcp.client.request.response.ResponseRequest;
import vcp.entity.Car;
import vcp.entity.Customer;
import vcp.entity.Site;
import vcp.entity.Subscription;
import vcp.enums.SubscriptionType;
import vcp.server.DAO.CarDAO;
import vcp.server.DAO.CustomerDAO;
import vcp.server.DAO.SiteDAO;
import vcp.server.DAO.SubscriptionDAO;
import vcp.server.interfaces.IServer;
import vcp.server.utility.Constants.TableNames;

/**
 * 
 * @author VCP team
 *         <p>
 *         subscription creation for user all user can create different
 *         subscription types this one update the DB and send update back to the
 *         GUI view of subscription order in the personal menu
 *         </p>
 * @see RequestHandler <SubmitSubscriptionFormRequest>
 */
public class SubmitSubscriptionFormRequestHandler extends RequestHandler <SubmitSubscriptionFormRequest>
{
	/**
	 * get the server to operate the request
	 * 
	 * @param server
	 */
	public SubmitSubscriptionFormRequestHandler ( IServer server )
	{
		super(server);
	}

	@Override
	public void execute ( SubmitSubscriptionFormRequest request, ConnectionToClient client )
	{
		SubscriptionForm form = request.getSubmitedForm();
		ResponseRequest response = new ResponseRequest(request.getRequestID(), null);

		ArrayList <Serializable> serializableInfo = new ArrayList <>();

		if ( form.getSubscription().getSubscriptionType() == SubscriptionType.ORDER_AHEAD )
		{
			this.trySubscribeRegularSubscription(form, serializableInfo);
		}
		else if ( form.getSubscription().getSubscriptionType() == SubscriptionType.CASUAL_SUBSCRIBER )
		{
			this.trySubscribeCasualSubscription(form, serializableInfo);
		}
		else
		{
			this.trySubscribeFullSubscription(form, serializableInfo);
		}

		response.setData(serializableInfo);
		this.sendResponse(response, client);
	}

	/**
	 * try to create new order ahead subscription
	 * 
	 * @param form
	 * @param serializableInfo
	 */
	private void trySubscribeRegularSubscription ( SubscriptionForm form, ArrayList <Serializable> serializableInfo )
	{
		CarDAO carDAO = new CarDAO();
		Car car = carDAO.findByID(form.getCarID());
		if ( this.isCorrectData(form, car) )
		{
			serializableInfo.add("You can't apply this subscription sorry");
		}
		else
		{
			CustomerDAO customerDAO = new CustomerDAO();
			Customer customer = customerDAO.findByID(form.getSubscription().getCustomerID());
			SubscriptionDAO subscriptionDAO = new SubscriptionDAO();
			Subscription subscription = subscriptionDAO.create();

			subscription.setSubscribtionID(this.server.getGeneratedID(TableNames.SUBSCRIPTION));
			subscription.setCustomerID(customer.getCustomerID());
			subscription.setArrivalDate(form.getSubscription().getArrivalDate());
			subscription.setCars(form.getSubscription().getCars());
			subscription.setEndDate(form.getSubscription().getEndDate());
			subscription.setEstimatedLeaveDate(form.getSubscription().getEstimatedLeaveDate());
			subscription.setSite(form.getSubscription().getSite());
			subscription.setStartDate(form.getSubscription().getStartDate());
			subscription.setSubscriptionType(SubscriptionType.ORDER_AHEAD);
			subscriptionDAO.save(subscription);

			this.saveNewCar(form, carDAO, customer, subscription);

			SiteDAO siteDAO = new SiteDAO();
			Site site = siteDAO.findByID(form.getSubscription().getSite().getSiteID());
			int hourOfPark = Minutes.minutesBetween(form.getSubscription().getArrivalDate(), form.getSubscription().getEstimatedLeaveDate()).getMinutes();
			hourOfPark = ( hourOfPark / 60 ) + 1;
			float toPay = site.getOrderAheadPricePerHour() * hourOfPark;
			customer.setBalance(customer.getBalance() - toPay);
			customerDAO.updateCustomerBalance(customer.getCustomerID(), customer.getBalance());
			customerDAO.updateCustomerBalance(customer.getCustomerID(), ( customer.getBussinessClass() + 1 ));

			serializableInfo.add(subscription);
			serializableInfo.add("You create new subscription thank you please");
			serializableInfo.add(new Float(customer.getBalance()));
		}
	}

	/**
	 * check if the form filled correct
	 * 
	 * @param form
	 * @param car
	 * @return true if data is correct
	 */
	private boolean isCorrectData ( SubscriptionForm form, Car car )
	{
		return ( car != null ) || ( Minutes.minutesBetween(form.getSubscription().getArrivalDate(), form.getSubscription().getEstimatedLeaveDate()).getMinutes() > 0 );
	}

	/**
	 * Create and save new car
	 * 
	 * @param form
	 * @param carDAO
	 * @param customer
	 * @param subscription
	 */
	private void saveNewCar ( SubscriptionForm form, CarDAO carDAO, Customer customer, Subscription subscription )
	{
		Car car;
		car = carDAO.create();
		car.setCarID(form.getCarID());
		car.setCustomerID(customer.getCustomerID());
		car.setParkedOnSite(false);
		car.setSubscriptionID(subscription.getSubscribtionID());
		car.setArrivedTime(null);
		car.setLastCheckOutDate(null);
		carDAO.save(car);
	}

	/**
	 * create new casual subscription
	 * 
	 * @param form
	 * @param serializableInfo
	 */
	private void trySubscribeCasualSubscription ( SubscriptionForm form, ArrayList <Serializable> serializableInfo )
	{
		CarDAO carDAO = new CarDAO();
		Car car = carDAO.findByID(form.getCarID());
		if ( this.isCorrectData(form, car) )
		{
			serializableInfo.add("You can't apply this subscription sorry");
		}
		else
		{
			CustomerDAO customerDAO = new CustomerDAO();
			Customer customer = customerDAO.findByID(form.getSubscription().getCustomerID());
			car = carDAO.create();

			if ( form.getSubscriptionID() != null )
			{
				SubscriptionDAO subscriptionDAO = new SubscriptionDAO();
				Subscription subscription = subscriptionDAO.findByID(form.getSubscriptionID());
				this.saveNewCar(form, carDAO, customer, subscription);
				List <Car> carList = subscription.getCars();
				carList.add(car);
				subscription.setCars(carList);
				serializableInfo.add(subscription);
				serializableInfo.add("You successfully add new car to your subscription");
				serializableInfo.add(new Float(customer.getBalance()));
			}
			else
			{
				SubscriptionDAO subscriptionDAO = new SubscriptionDAO();
				Subscription subscription = subscriptionDAO.create();

				subscription.setSubscribtionID(this.server.getGeneratedID(TableNames.SUBSCRIPTION));
				subscription.setCustomerID(customer.getCustomerID());
				subscription.setArrivalDate(form.getSubscription().getArrivalDate());
				subscription.setCars(form.getSubscription().getCars());
				subscription.setEndDate(form.getSubscription().getStartDate().plus(28));
				subscription.setEstimatedLeaveDate(form.getSubscription().getEstimatedLeaveDate());
				subscription.setSite(form.getSubscription().getSite());
				subscription.setStartDate(form.getSubscription().getStartDate());
				subscription.setSubscribtionID(form.getSubscriptionID());
				subscription.setSubscriptionType(SubscriptionType.CASUAL_SUBSCRIBER);
				subscriptionDAO.save(subscription);

				SiteDAO siteDAO = new SiteDAO();
				Site site = siteDAO.findByID(form.getSubscription().getSite().getSiteID());

				customer.setBalance(customer.getBalance() - site.getCasualPriceSingleCar());
				customerDAO.updateCustomerBalance(customer.getCustomerID(), customer.getBalance());
				customerDAO.updateBussinessClass(customer.getCustomerID(), ( customer.getBussinessClass() + 1 ));

				serializableInfo.add(subscription);
				serializableInfo.add("You create new subscription thank you please");
				serializableInfo.add(new Float(customer.getBalance()));
			}

		}
	}

	/**
	 * create new full subscription
	 * 
	 * @param form
	 * @param serializableInfo
	 */
	private void trySubscribeFullSubscription ( SubscriptionForm form, ArrayList <Serializable> serializableInfo )
	{
		CarDAO carDAO = new CarDAO();
		Car car = carDAO.findByID(form.getCarID());
		if ( this.isCorrectData(form, car) )
		{
			serializableInfo.add("You can't apply this subscription sorry");
		}
		else
		{
			CustomerDAO customerDAO = new CustomerDAO();
			Customer customer = customerDAO.findByID(form.getSubscription().getCustomerID());
			car = carDAO.create();

			if ( form.getSubscriptionID() != null )
			{
				SubscriptionDAO subscriptionDAO = new SubscriptionDAO();
				Subscription subscription = subscriptionDAO.findByID(form.getSubscriptionID());
				this.saveNewCar(form, carDAO, customer, subscription);
				List <Car> carList = subscription.getCars();
				carList.add(car);
				subscription.setCars(carList);
				serializableInfo.add(subscription);
				serializableInfo.add("You successfully add new car to your subscription");
				serializableInfo.add(new Float(customer.getBalance()));
			}
			else
			{
				SubscriptionDAO subscriptionDAO = new SubscriptionDAO();
				Subscription subscription = subscriptionDAO.create();

				subscription.setSubscribtionID(this.server.getGeneratedID(TableNames.SUBSCRIPTION));
				subscription.setCustomerID(customer.getCustomerID());
				subscription.setArrivalDate(form.getSubscription().getArrivalDate());
				subscription.setCars(form.getSubscription().getCars());
				subscription.setEndDate(form.getSubscription().getStartDate().plus(28));
				subscription.setEstimatedLeaveDate(form.getSubscription().getEstimatedLeaveDate());
				subscription.setSite(form.getSubscription().getSite());
				subscription.setStartDate(form.getSubscription().getStartDate());
				subscription.setSubscribtionID(form.getSubscriptionID());
				subscription.setSubscriptionType(SubscriptionType.FULL_SUBSCRIBER);
				subscriptionDAO.save(subscription);

				SiteDAO siteDAO = new SiteDAO();
				Site site = siteDAO.findByID(form.getSubscription().getSite().getSiteID());

				customer.setBalance(customer.getBalance() - site.getFullPriceSingleCar());
				customerDAO.updateCustomerBalance(customer.getCustomerID(), customer.getBalance());
				customerDAO.updateBussinessClass(customer.getCustomerID(), ( customer.getBussinessClass() + 1 ));

				serializableInfo.add(subscription);
				serializableInfo.add("You create new subscription thank you please");
				serializableInfo.add(new Float(customer.getBalance()));
			}
		}
	}

}
